import type { extend } from 'dayjs'

interface IObject {
  [key: string]: any
}

// 导出一个函数，用于清除对象中的空值
export function clearEmptyValues(obj: IObject) {
  // 深度克隆对象
  const objClone = deepClone(obj)
  // 遍历对象的每一个属性
  for (const key in objClone) {
    // 判断属性是否为对象自身的属性
    if (Object.prototype.hasOwnProperty.call(objClone, key)) {
      // 获取属性的值
      const val = objClone[key]
      // 判断属性的值是否为空
      if (val == null || val === undefined || val === '') {
        // 如果为空，则删除该属性
        delete objClone[key]
      }
    }
  }
  return objClone
}

/**
 * 深度克隆
 * @param value 需要克隆的对象
 * @param hash
 * @returns
 */
export function deepClone<T extends any>(value: T, hash = new WeakMap()): T {
  // 如果传入的值是null或者不是对象，则直接返回该值
  if (value === null || typeof value !== 'object') {
    return value
  }
  // 如果传入的值已经被克隆过，则直接返回克隆后的值
  if (hash.has(value)) {
    return hash.get(value)
  }
  // 如果传入的值是Date类型，则返回一个新的Date对象
  if (value instanceof Date) {
    return new Date(value.getTime()) as T
  }
  // 如果传入的值是RegExp类型，则返回一个新的RegExp对象
  if (value instanceof RegExp) {
    return new RegExp(value) as T
  }
  // 如果传入的值是Map类型，则返回一个新的Map对象
  if (value instanceof Map) {
    const map = new Map()
    hash.set(value, map)
    value.forEach((v, k) => {
      map.set(k, deepClone(v, hash))
    })
    return map as T
  }
  // 如果传入的值是Set类型，则返回一个新的Set对象
  if (value instanceof Set) {
    const set = new Set()
    hash.set(value, set)
    value.forEach((v) => {
      set.add(deepClone(v, hash))
    })
    return set as T
  }
  // 如果传入的值是ArrayBuffer类型，则返回一个新的ArrayBuffer对象
  if (value instanceof ArrayBuffer) {
    return value.slice(0) as T
  }
  // 如果传入的值是ArrayBuffer的视图类型，则返回一个新的视图对象
  if (ArrayBuffer.isView(value)) {
    return new (value.constructor as any)(value) as T
  }
  // 如果传入的值是Symbol类型，则返回一个新的Symbol对象
  if (typeof value === 'symbol') {
    return Object(Symbol.prototype.valueOf.call(value)) as T
  }
  // 如果传入的值是数组，则返回一个新的空数组，否则返回一个新的对象
  const objCopy = Array.isArray(value)
    ? []
    : Object.create(Object.getPrototypeOf(value))
  // 将传入的值和克隆后的值放入hash中
  hash.set(value, objCopy)
  // 遍历传入的值的属性，将属性值进行深度克隆，并赋值给克隆后的对象
  Reflect.ownKeys(value).forEach((key) => {
    ;(objCopy as any)[key] = deepClone((value as any)[key], hash)
  })
  // 返回克隆后的对象
  return objCopy as T
}
